package trade

import (
	"errors"
	"fmt"
	"strings"
	"sync"

	"github.com/sirupsen/logrus"
)

type TradeExt struct {
	*Trade
	UserID    string
	AccountID []string // 子号
	chReady   chan TAPIINT32
	// 品种@类型@交易所
	//
	// ("%s@%c@%s", info.CommodityNo.String(), info.CommodityType, info.ExchangeNo.String())
	Product map[string]TapAPICommodityInfo
	// 品种@合约1@合约2@类型@交易所@CP@行权价
	//
	// ("%s@%s@%s@%c@%s@%c@%s", info.CommodityNo.String(), info.ContractNo1.String(), info.ContractNo2.String(), info.CommodityType, info.ExchangeNo.String(), info.CallOrPutFlag1, info.StrikePrice1.String())
	Instrument map[string]TapAPITradeContractInfo

	// fmt.Sprintf("%s|%s", info.AccountNo.String(), info.Key())
	// key: ("%s@%s@%c@%s", info.CommodityNo.String(), info.ContractNo.String(), info.CommodityType, info.ExchangeNo.String())
	//
	// TapAPIPositionSummary
	MapPositionSummary sync.Map

	// MatchNo:TapAPIFillInfo
	MapTrade sync.Map

	// 委托响应
	// OnOrder func(info *TapAPIOrderInfo)
	// 成交响应
	OnTrade func(info *TapAPIFillInfo)
	// 持仓响应
	OnPosition func(info *TapAPIPositionSummary)
}

func NewTradeExt(appID, authCode string) (*TradeExt, error) {
	var err error
	ext := new(TradeExt)
	ext.chReady = make(chan TAPIINT32)
	ext.Trade, err = NewTrade(appID, authCode)
	if err != nil {
		return nil, err
	}
	ext.Instrument = make(map[string]TapAPITradeContractInfo)
	ext.Product = make(map[string]TapAPICommodityInfo)

	return ext, nil
}

func (t *TradeExt) ReqConnect(tradeIP string, port uint) error {
	t.OnRspQryCommodity = func(sessionID TAPIUINT32, errorCode TAPIINT32, isLast TAPIYNFLAG, info *TapAPICommodityInfo) {
		if info != nil {
			key := fmt.Sprintf("%s@%c@%s", info.CommodityNo.String(), info.CommodityType, info.ExchangeNo.String())
			if _, exists := t.Product[key]; exists {
				fmt.Println(key, " exists!")
			} else {
				t.Product[key] = *info
			}
		}
		if isLast == APIYNFLAG_YES {
			fmt.Println("查询品种: ", len(t.Product))
			var s TAPIUINT32
			res := t.QryContract(&s, &TapAPICommodity{}) // 查合约
			if res != 0 {
				fmt.Println("查合约: ", t.GetITapErrorDescribe(FromCint32(res)))
				// 登录成功通知
				t.chReady <- FromCint32(res)
			}
		}
	}
	t.OnRspQryContract = func(sessionID TAPIUINT32, errorCode TAPIINT32, isLast TAPIYNFLAG, info *TapAPITradeContractInfo) {
		if info != nil {
			// key := fmt.Sprintf("%s@%s@%c@%s", info.CommodityNo.String(), info.ContractNo1.String(), info.CommodityType)
			// if info.CommodityType == "" {
			key := fmt.Sprintf("%s@%s@%s@%c@%s@%c@%s", info.CommodityNo.String(), info.ContractNo1.String(), info.ContractNo2.String(), info.CommodityType, info.ExchangeNo.String(), info.CallOrPutFlag1, info.StrikePrice1.String())
			// }
			if _, exists := t.Instrument[key]; exists {
				// fmt.Println(key, " is Exists!")
			} else {
				t.Instrument[key] = *info
			}
		}
		if isLast == APIYNFLAG_YES {
			fmt.Printf("查合约: %d\n", len(t.Instrument))
			go func() {
				// 查所有持仓
				var s TAPIUINT32
				res := t.QryPositionSummary(&s, &TapAPIPositionQryReq{})
				if res != 0 {
					fmt.Println("查持仓: ", t.GetITapErrorDescribe(FromCint32(res)))
					// 登录成功通知
					t.chReady <- FromCint32(res)
				}
			}()
		}
	}
	// 用于查询持仓的响应
	t.OnRspQryPositionSummary = func(sessionID TAPIUINT32, errorCode TAPIINT32, isLast TAPIYNFLAG, info *TapAPIPositionSummary) {
		if info != nil {
			key := fmt.Sprintf("%s|%s", info.AccountNo.String(), info.Key())
			t.MapPositionSummary.Store(key, *info)
		}
		if isLast == APIYNFLAG_YES {
			// 登录成功通知
			t.chReady <- FromInt32(0)
		}
	}
	t.OnRspQryAccount = func(sessionID, errorCode TAPIUINT32, isLast TAPIYNFLAG, info *TapAPIAccountInfo) {
		if info != nil {
			t.AccountID = append(t.AccountID, info.AccountNo.String())
		}
		if isLast == APIYNFLAG_YES {
			var s TAPIUINT32
			res := t.QryCommodity(&s) // 查品种
			if res != 0 {
				fmt.Println("查品种: ", t.GetITapErrorDescribe(FromCint32(res)))
				// 登录成功通知
				t.chReady <- FromCint32(res)
			}
		}
	}
	t.OnAPIReady = func(errorCode TAPIINT32) {
		if errorCode.Int32() == 0 {
			var s TAPIUINT32
			res := t.QryAccount(&s, &TapAPIAccQryReq{})
			if res != 0 {
				fmt.Println("查子交易帐号: ", t.GetITapErrorDescribe(FromCint32(res)))
				// 登录成功通知
				t.chReady <- FromCint32(res)
			}
		} else {
			logrus.Error(t.GetITapErrorDescribe(errorCode))
		}
	}

	t.OnConnect = func(HostAddress string) {
		fmt.Println("连接前置: ", HostAddress)
	}
	t.OnRspLogin = func(errorCode TAPIINT32, loginRspInfo *TapAPITradeLoginRspInfo) {
		if errorCode.Int32() == 0 {
			fmt.Printf("%+v\n", *loginRspInfo)
		} else {
			fmt.Printf("登录错误: {%d:%s}\n", errorCode.Int32(), t.GetITapErrorDescribe(errorCode))
			t.chReady <- errorCode
		}
	}
	t.OnDisconnect = func(reasonCode TAPIINT32) {
		fmt.Printf("断开: {%d:%s}\n", reasonCode.Int32(), t.GetITapErrorDescribe(reasonCode))
	}
	t.OnRtnPosition = func(info *TapAPIPositionInfo) {
		// fmt.Printf("OnRtnPosition: %+v", info)
	}
	t.OnRtnPositionProfit = func(info *TapAPIPositionProfitNotice) {
		// fmt.Printf("OnRtnPositionProfit: %+v", *info)
	}
	t.OnRtnPositionSummary = func(info *TapAPIPositionSummary) {
		key := fmt.Sprintf("%s|%s", info.AccountNo.String(), info.Key())
		t.MapPositionSummary.Store(key, *info)
		if t.OnPosition != nil {
			t.OnPosition(info)
		}
	}
	t.OnRspOrderAction = func(sessionID TAPIUINT32, errorCode TAPIINT32, info *TapAPIOrderActionRsp) {
		// fmt.Println(info.ActionType)
	}
	t.OnRtnOrder = func(info *TapAPIOrderInfoNotice) {
		fmt.Printf("OnRtnOrder, sessionID:%d {%d:%s}\n", info.SessionID.Uint32(), info.ErrorCode.Uint32(), t.GetITapErrorDescribe(TAPIINT32(info.ErrorCode)))
	}
	t.OnRtnSpecialOrder = func(info *TapAPISpecialOrderInfo) {
		fmt.Printf("OnRtnSpecialOrder, sessionID:%d %d:%s\n", info.SessionID.Uint32(), info.ErrorCode, t.GetITapErrorDescribe(TAPIINT32(info.ErrorCode)))
	}
	t.OnRtnFill = func(info *TapAPIFillInfo) {
		if t.OnTrade == nil {
			// fmt.Printf("OnRtnFill %+v\n", *info)
			t.MapTrade.Store(info.MatchNo, *info)
		} else {
			t.OnTrade(info)
		}
	}

	if res := t.SetHostAddress(tradeIP, TAPIUINT16(port)); res != 0 {
		msg := t.GetITapErrorDescribe(FromCint32(res))
		return errors.New(msg)
	}
	return nil
}

func (t *TradeExt) ReqLogin(userID, passWord string) error {
	logAuth := TapAPITradeLoginAuth{
		ISModifyPassword: APIYNFLAG_NO,
	}
	copy(logAuth.UserNo[:], userID)
	copy(logAuth.Password[:], passWord)
	if res := t.Login(&logAuth); res != 0 {
		msg := t.GetITapErrorDescribe(FromCint32(res))
		return errors.New(msg)
	}
	res := <-t.chReady
	if res.Int32() != 0 { // 登录错误
		return fmt.Errorf("%d:%s", res.Int32(), t.GetITapErrorDescribe(res))
	}
	t.UserID = userID
	return nil
}

func (t *TradeExt) ReqLogout() error {
	res := t.Disconnect()
	t.Trade = nil
	// t.FreeITapTradeAPI(t.api) // 崩溃
	if res != 0 {
		return errors.New(t.GetITapErrorDescribe(FromCint32(res)))
	}
	return nil
}

func (t *TradeExt) ReqOrderInsert(exchangeID, commodityNo, contractNo string, orderType TAPIOrderTypeType, price float64, qty int, side TAPISideType, commodityType TAPICommodityType, accountID ...string) (session uint, clientNo string, err error) {
	account := t.UserID
	if len(accountID) > 0 {
		account = accountID[0]
	}
	var order = TapAPINewOrder{}
	copy(order.AccountNo[:], []byte(account))
	copy(order.ExchangeNo[:], []byte(exchangeID))
	copy(order.CommodityNo[:], []byte(commodityNo))
	copy(order.ContractNo[:], []byte(contractNo))
	// copy(order.ContractNo2[:], contractNo) // 提示: 下单无效的合约

	order.OrderType = orderType // 限价 市价...
	order.OrderPrice = FromFloat64(price)
	order.OrderQty = FromUint32(uint32(qty))
	order.OrderMinQty = FromUint32(uint32(1))

	order.HedgeFlag = TAPI_HEDGEFLAG_NONE
	// order.ClientID
	// order.ExpireTime // GTD 时使用
	order.TimeInForce = TAPI_ORDER_TIMEINFORCE_GFD

	order.OrderSide = side              // 买卖
	order.CommodityType = commodityType // 品种类型

	order.CallOrPutFlag = TAPI_CALLPUT_FLAG_NONE
	order.CallOrPutFlag2 = TAPI_CALLPUT_FLAG_NONE

	order.TimeInForce = TAPI_ORDER_TIMEINFORCE_GFD // 有效期
	order.IsRiskOrder = APIYNFLAG_NO
	order.PositionEffect = TAPI_PositionEffect_NONE
	order.PositionEffect2 = TAPI_PositionEffect_NONE
	order.HedgeFlag = TAPI_HEDGEFLAG_NONE
	// {-12035:输入错误的:TAPITacticsTypeType}
	// order.TacticsType = TAPI_TACTICS_TYPE_ATUO
	order.TacticsType = TAPI_TACTICS_TYPE_NONE    // 策略单类型
	order.OrderSource = TAPI_ORDER_SOURCE_PROGRAM // 来源
	order.AddOneIsValid = APIYNFLAG_NO

	order.TriggerCondition = TAPI_TRIGGER_CONDITION_NONE
	order.TriggerPriceType = TAPI_TRIGGER_PRICE_NONE

	var s TAPIUINT32
	var c TAPISTR_50
	res := t.InsertOrder(&s, &c, &order)
	if res != 0 {
		err = fmt.Errorf("委托: {%d:%s}", res, t.GetITapErrorDescribe(FromCint32(res)))
		return
	}
	session = uint(s.Uint32())
	clientNo = c.String()
	return
}

func (t *TradeExt) ReqOrderInsertLMT(exchangeID, commodityNo, contractNo string, price float64, qty int, side TAPISideType, commodityType TAPICommodityType) (session uint, clientNo string, err error) {
	return t.ReqOrderInsert(exchangeID, commodityNo, contractNo, TAPI_ORDER_TYPE_LIMIT, price, qty, side, commodityType)
}

func (t *TradeExt) ReqOrderInsertMKT(exchangeID, commodityNo, contractNo string, qty int, side TAPISideType, commodityType TAPICommodityType) (session uint, clientNo string, err error) {
	return t.ReqOrderInsert(exchangeID, commodityNo, contractNo, TAPI_ORDER_TYPE_MARKET, 0, qty, side, commodityType)
}

func (t *TradeExt) ReqQryPosition(accountID string) []TapAPIPositionSummary {
	res := make([]TapAPIPositionSummary, 0)
	t.MapPositionSummary.Range(func(key, value any) bool {
		// 删除指定帐号的持仓
		if strings.HasPrefix(key.(string), accountID+"|") {
			res = append(res, value.(TapAPIPositionSummary))
		}
		return true
	})
	return res
}
